package com.ztom.agent.asm.plugin;

import com.ztom.agent.bean.InjectClassInfo;
import com.ztom.agent.log.Logger;
import com.ztom.agent.util.Wildcard;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.AdviceAdapter;

import java.util.Arrays;
import java.util.List;

import static org.objectweb.asm.Opcodes.ASM5;

/**
 * @author ZhangTao
 */
public class PluginClassVisitor extends ClassVisitor {

    private String innerClassName;

    public PluginClassVisitor(final ClassVisitor cv, String innerClassName) {
        super(ASM5, cv);
        this.innerClassName = innerClassName;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        Logger.debug("PluginClassVisitor.visitMethod(" + access + ", " + name + ", " + desc + ", " + signature + ", " + Arrays.toString(exceptions) + ")");

        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

        List<InjectClassInfo> classInfoList = PluginInfoHolder.getPluginMap().get(innerClassName);
        for (InjectClassInfo classInfo : classInfoList) {
            String methodName = classInfo.getMethodName();
            String methodDesc = classInfo.getMethodDesc();
            if (!Wildcard.equalsOrMatch(methodName, name) || !Wildcard.equalsOrMatch(methodDesc, desc)) {
                continue;
            }
            Class<? extends AdviceAdapter> clazz = classInfo.getClazz();
            try {
                return ConstructorUtils.invokeConstructor(clazz, mv, access, name, desc, classInfo);
            } catch (Exception e) {
                Logger.error("PluginClassVisitor.visitMethod(" + access + ", " + name + ", " + desc + ", " + signature + ", " + Arrays.toString(exceptions) + ")", e);
            }
            return mv;
        }

        return mv;
    }
}
